package com.example.flow.biz.impl;

import com.example.flow.biz.FlowApproveApplyDetailBiz;
import com.example.flow.biz.FlowBiz;
import com.example.flow.biz.FlowTaskApproveBiz;
import com.example.flow.constant.FlowConstant;
import com.example.flow.dao.FlowApproveApplyDao;
import com.example.flow.dao.model.FlowApproveApply;
import com.example.flow.dao.model.FlowApproveApplyDetail;
import com.example.flow.dao.model.FlowOrder;
import com.example.flow.dao.model.FlowTaskApprove;
import com.example.flow.enums.EnumApproveStatus;
import com.example.flow.enums.EnumFinishFlag;
import com.example.flow.enums.EnumReply;
import com.example.flow.flow.core.FlowEngine;
import com.example.flow.request.CommonApproveRequest;
import com.example.flow.request.FlowStartRequest;
import com.example.flow.request.SubmitRequest;
import com.example.flow.sequence.SequenceTool;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author tangaq
 * @date 2020/11/25
 */
@Service
public class FlowBizImpl implements FlowBiz {
    @Autowired
    private FlowEngine flowEngine;
    @Autowired
    private FlowTaskApproveBiz taskApproveBiz;
    @Autowired
    private FlowApproveApplyDao approveApplyDao;
    @Autowired
    private FlowApproveApplyDetailBiz approveApplyDetailBiz;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String submit(SubmitRequest request) {
        // 1.加redis锁relateId+processId
        // 2.校验审批单是否重复发起:通过关联编号relateId查询未完成审批单
        // 3.校验start节点校验前置拦截器checkInterceptor，返回relateId
        // 4.通过applyId判断是否是创建工单还是更新工单 saveFlowApproveApply
        // 4.1创建工单审批记录 插入flowapprove和flowapproveInfo
        String applyId = request.getApplyId();
        if (StringUtils.isBlank(request.getApplyId())) {
            applyId = SequenceTool.nextId();
            request.setApplyId(applyId);
            this.saveFlowApproveApply(request);
        }
        // 4.2 更新工单审批记录 部分审批的校验接口会返回关联编号relateId，不为空则更新flowapproveApply和flowapproveApplyInfo关联编号字段
        // 5.启动流程
        FlowOrder order = this.startFlow(request.getProcessId(), request.getApplyId(), request.getOperatorId(),
                request.getContent());
        // 6.保存任务-审批记录 saveFlowTaskApprove
        this.saveFlowTaskApprove(request, order);
        return order.getOrderId();
    }

    @Override
    public FlowOrder startFlow(FlowStartRequest request) {
        return this.startFlow(request.getProcessId(), null, request.getOperatorId(), request.getOrderContent());
    }

    private FlowOrder startFlow(String processId, String applyId, String operator, String orderContent) {
        Map<String, Object> map = new HashMap<>();
        map.put(FlowConstant.ORDER_CONTENT, orderContent);
        map.put(FlowConstant.APPLY_ID, StringUtils.isBlank(applyId) ? SequenceTool.nextId() : applyId);
        map.put(FlowConstant.COMMON_APPROVAL_FLAG, true);
        return flowEngine.startInstanceById(processId, map);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean commonApproval(CommonApproveRequest request) {
        Map<String, Object> map = new HashMap<>();
        for (Map.Entry<String, String> kv : request.getParams()
                .entrySet()) {
            map.put(kv.getKey(), kv.getValue());
        }
        EnumReply enumReply = EnumReply.find(request.getReply());
        if (enumReply == null) {
            throw new IllegalArgumentException("reply参数有误");
        }
        map.put(FlowConstant.REPLY_RESULT, enumReply
                .getCode());
        //审批结果放到上下文变量了，在连接器取得后更新相应的进件表里去\
        this.commonApproval(request.getTaskId(), request.getOperatorId(), map, enumReply);
        return true;
    }

    private void commonApproval(String taskId, String operator, Map<String, Object> param, EnumReply reply) {
        switch (reply) {
            case ADOPT:
                flowEngine.executeTask(taskId, param);
                break;
            case REFUSE:
                flowEngine.executeAndJump(taskId, param, "end");
                break;
            default:
                throw new RuntimeException("审批策略未找到");
        }

    }

    private void saveFlowApproveApply(SubmitRequest request) {
        FlowApproveApply flowApproveApply = new FlowApproveApply();
        flowApproveApply.setApplyId(request.getApplyId());
        flowApproveApply.setProcessId(request.getProcessId());
        flowApproveApply.setCreateOpetatorId(request.getOperatorId());
        flowApproveApply.setStatus(EnumApproveStatus.TODO.getCode());
        flowApproveApply.setFinishFlag(EnumFinishFlag.NO.getCode());
        flowApproveApply.setCreateTime(new Date());
        flowApproveApply.setCreateOpetatorId(request.getOperatorId());
        approveApplyDao.saveFlowApproveApply(flowApproveApply);
        FlowApproveApplyDetail detail = new FlowApproveApplyDetail();
        detail.setApplyId(flowApproveApply.getApplyId());
        detail.setContent(request.getContent());
        approveApplyDetailBiz.saveApproveApplyDetail(detail);
    }

    private void saveFlowTaskApprove(SubmitRequest request, FlowOrder order) {
        FlowApproveApply approveApply = approveApplyDao.queryOne(request.getApplyId(), null);
        FlowTaskApprove flowTaskApprove = new FlowTaskApprove();
        flowTaskApprove.setId(SequenceTool.nextId());
        flowTaskApprove.setApplyId(request.getApplyId());
        flowTaskApprove.setOrderId(order.getOrderId());
        flowTaskApprove.setTaskId(approveApply.getCurrentTaskId());
        flowTaskApprove.setTaskName(approveApply.getCurrentNodeName());
        flowTaskApprove.setOperatorId(approveApply.getCurrentOperatorId());
        flowTaskApprove.setCreateTime(new Date());
        taskApproveBiz.saveCommonApproval(flowTaskApprove);
    }

}
